﻿using PeterKottas.DotNetCore.WindowsService.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
using NLog;
using PeterKottas.DotNetCore.WindowsService.Base;
using SuperSocket.ClientEngine;
using SuperSocket.ProtoBase;
using System.Net;
using System.Linq;
using Newtonsoft.Json;
using WebSvrUpdaterCore.Models;
using Microsoft.Extensions.Configuration;
using WebSvrUpdaterCore.IISAdmin;

namespace WebSvrUpdaterCore
{
    class WebSvrUpdaterService : MicroService, IMicroService
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();
        private IMicroServiceController _controller;
        private EasyClient<MsgPacket> _client;
        private IConfiguration _configuration;
        private string _clientId;
        //更新通道
        private int _updateChannel = 3;
        private string _serverAddress;
        private int _serverPort;
        //心跳包间隔
        private int _pingInterval = 30 * 1000;
        //断线重试次数
        private int _closeRetry = 5;
        //断线重试间隔
        private int _retryInterval = 30 * 1000;

        private bool _isLive = false;

        private int currentRetryTimes = 0;
        private DateTime lastRetryTime;

        private int _waitStatuInterval = 5 * 10;
        private IPEndPoint _serverEndPoint;
        private CommandHandle _commandHandle;
        public WebSvrUpdaterService() : this(null)
        {
        }

        public WebSvrUpdaterService(IMicroServiceController controller)
        {

            _controller = controller;
            var builder = new ConfigurationBuilder()
                .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                .AddJsonFile("appsettings.json", false);
            _configuration = builder.Build();
            _clientId = _configuration["uid"];
            _serverAddress = _configuration["SeverAddress"];
            var channel = _configuration["UpdateChannel"];
            if (!string.IsNullOrEmpty(channel))
            {
                int.TryParse(channel, out _updateChannel);

            }
            if (string.IsNullOrEmpty(_serverAddress))
            {
                throw new ArgumentNullException("SuperSocket服务器地址不允许为空");
            }
            _serverPort = _configuration.GetValue<int>("ServerPort");
            if(_serverPort < 1)
            {
                _serverPort = 9007;
            }
            _pingInterval = _configuration.GetValue<int>("PingInterval") * 1000;
            _closeRetry = _configuration.GetValue<int>("CloseRetry");
            _retryInterval = _configuration.GetValue<int>("RetryInterval") * 1000;
        }
        public void Start()
        {
            try
            {
                base.StartBase();
                _logger.Info("WebSvrUpdaterCore服务启动");

                _client = new EasyClient<MsgPacket>();
                _client.Initialize(new MsgReceiveFilter());

                _client.Connected += Client_Connected;
                _client.Closed += Client_Closed;
                _client.NewPackageReceived += Client_NewPackageReceived;
                _client.Error += Client_Error;
                /*
                _client.Security = new SecurityOption()
                {
                    Credential = new System.Net.NetworkCredential("admin", "test")
                };
                */
                _errOccur = false;
                _serverEndPoint = new IPEndPoint(IPAddress.Parse(_serverAddress), _serverPort);
                _commandHandle = new CommandHandle(_client, _clientId, _logger,_serverEndPoint);
                ConnectServer();
                lastRetryTime = DateTime.Now;
#if DEBUG
                var sites = IISHelper.GetAllSite();
                Console.WriteLine("============================站点==========================");
                Console.ForegroundColor = ConsoleColor.DarkGreen;
                //var firstBindInfo = sites[0].Bindings[0];
                //var host = firstBindInfo.Host;
                //if (string.IsNullOrEmpty(host) && "0.0.0.0" == firstBindInfo.EndPoint.Address.ToString())
                //{
                //    host = "localhost";
                //}
                //var url = $"{firstBindInfo.Protocol}://{host}:{firstBindInfo.EndPoint.Port}/";
                foreach (var site in sites)
                {
                    StringBuilder siteBuff = new StringBuilder();

                    siteBuff.AppendLine("----------------------------Site Info--------------------------------");
                    var strBuff = new StringBuilder();
                    site.Attributes.ToList().ForEach(siteEl =>
                    {
                        strBuff.AppendLine($"Name={siteEl.Name} ,Value={siteEl.Value};");
                    });
                    strBuff.AppendLine($"程序池名称：{site.ApplicationDefaults.ApplicationPoolName}，程序路径：{site.Applications["/"].Path}，物理路径:{site.Applications["/"].VirtualDirectories["/"].PhysicalPath}");
                    siteBuff.AppendLine(strBuff.ToString());
                    //绑定信息
                    var bindsInfo = new StringBuilder();
                    foreach (var bi in site.Bindings)
                    {
                        //bindsInfo.AppendLine($"IP={bi.EndPoint.Address.ToString()},Port ={bi.EndPoint.Port},Host={bi.Host},Protocol={bi.Protocol},Schema={bi.Schema.Name}");
                        StringBuilder strBuf = new StringBuilder();
                        bindsInfo.AppendLine("----------------------------Bindings Info--------------------------------");
                        bi.Attributes.ToList().ForEach(el =>
                        {
                            strBuf.AppendLine($"Name={el.Name} ,Value={el.Value};");
                        });
                        bindsInfo.Append(strBuf.ToString());
                    }

                    var bindStr = bindsInfo.ToString();
                    siteBuff.AppendLine(bindStr);
                    //var siteStr = string.Format($"ID={site.Id},Name={site.Name},ServerAutoStart={site.ServerAutoStart},State={site.State},Bindings={bindStr}");
                    Console.WriteLine(siteBuff.ToString());
                    bindsInfo.Append("----------------------------Site End--------------------------------");
                    
                }
                Console.ForegroundColor = ConsoleColor.White;

                Console.WriteLine("=========================================================");

                var pools = IISHelper.GetAllAppPools();

                Console.WriteLine("============================程序池==========================");
                Console.ForegroundColor = ConsoleColor.DarkGreen;
                foreach (var p in pools)
                {
                    PrintAppPool(p);
                }
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("删除TestPool01程序池");
                IISHelper.DeleteAppPool("TestPool01");

               

                Console.WriteLine("添加TestPool程序池");
                var poolModel = new AppPoolModel() { Name = "TestPool" };
                var newPool = IISHelper.CreateAppPool(poolModel);
                Console.WriteLine("等待{0}毫秒后获取程序池状态", _waitStatuInterval);
                System.Threading.Thread.Sleep(_waitStatuInterval);
                PrintAppPool(newPool);

                Console.WriteLine("修改TestPool为TestPool01程序池");
                var modifyPool = new AppPoolModel
                {
                    AutoStart = true,
                    Enable32BitAppOnWin64 = true,
                    Name = "TestPool01",
                    ManagedRuntimeVersion = "v4.0"
                };
                
                var modifiedPool = IISHelper.UpdateAppPool("TestPool", modifyPool);
                
                Console.WriteLine("等待{0}毫秒后获取程序池状态", _waitStatuInterval);
                System.Threading.Thread.Sleep(_waitStatuInterval);
                System.Threading.Thread.Sleep(5 * 100);
                PrintAppPool(modifiedPool);

#endif
                Console.ForegroundColor = ConsoleColor.White;

            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Start()");
                //Console.WriteLine("socket连接错误,错误信息:{0}", ex.Message);

            }

        }


        public void Stop()
        {
            _logger.Info("WebSvrUpdaterCore服务停止");
            if (_client != null && _client.IsConnected)
            {
                StopPing();
                Timers.Stop("ReconnectServer");
                _commandHandle.Bye();
                _client.Close();
                _client = null;
                _logger.Info("SuperSocket关闭");
                //Console.WriteLine("SuperSocket关闭");
            }
            base.StopBase();
        }



        private void PrintAppPool(Microsoft.Web.Administration.ApplicationPool pool)
        {
            StringBuilder strBuf = new StringBuilder();

            foreach (var e in pool.Attributes)
            {
                strBuf.AppendLine($"Name={e.Name},Value={e.Value};");
            }
            Console.WriteLine("------------------------------------------------------------");
            Console.WriteLine(strBuf.ToString());
            //Console.WriteLine($"Name={p.Name},AutoStart={p.AutoStart},State={p.State},ManagedPipelineMode={p.ManagedPipelineMode.ToString()},ManagedRuntimeVersion={p.ManagedRuntimeVersion}");
            Console.WriteLine("------------------------------------------------------------");
        }

        private bool ConnectServer()
        {
            if (_client == null) return false;
            if (_client.IsConnected) return true;
          
            var task = _client.ConnectAsync(_serverEndPoint);
            if (!task.Result)
            {
                _logger.Info("连接服务器失败");
                Console.WriteLine("连接服务器失败");
                return false;
            }
            return true;
        }

        //心跳包，保持tcp连接
        private void StartPing()
        {
            base.Timers.Start("KeepLive", _pingInterval, () =>
            {
                _commandHandle.Ping();
            }, err =>
            {
                _logger.Error(err);
                Console.WriteLine("ping定时器发生异常,错误信息:", err.Message);
            });
        }


        private void StopPing()
        {
            base.Timers.Stop("KeepLive");

        }

        private bool _errOccur = false;
        private void Client_Error(object sender, ErrorEventArgs e)
        {
            _isLive = false;
            _logger.Error(e.Exception, "socket连接错误");
            Console.WriteLine("socket连接错误,错误信息:{0}", e.Exception.Message);
            if (!_errOccur)
            {
                Timers.Start("ReconnectServer", _retryInterval, ReconnectServer);
            }
            _errOccur = true;
        }

        /// <summary>
        /// 重连服务器
        /// </summary>
        private void ReconnectServer()
        {          
            if (_closeRetry > 0 ||  _closeRetry == -1)
            {
                if (!_isLive)
                {
                    if (currentRetryTimes > _closeRetry && _closeRetry != -1)
                    {
                        Timers.Stop("ReconnectServer");
                        _logger.Info("停止重连");
                        return;
                    }
                    else
                    {
                        ConnectServer();
                        currentRetryTimes++;
                        lastRetryTime = DateTime.Now;

                        _logger.Info("第{0}次断线重连", currentRetryTimes);
                    }

                }
                else
                {
                    Timers.Stop("ReconnectServer");
                    _logger.Info("停止重连");

                }
            }

        }
        private void Client_NewPackageReceived(object sender, PackageEventArgs<MsgPacket> e)
        {
            _isLive = true;
            if (_logger.IsTraceEnabled)
            {
                var msg = JsonConvert.SerializeObject(e.Package);
                _logger.Trace(msg);
            }
            if (!e.Package.IsVaild)
            {
                _logger.Error("数据包校验失败,包内容:" + JsonConvert.SerializeObject(e.Package));
                return;
            }
#if DEBUG
            Console.WriteLine("接收到服务器消息:" + JsonConvert.SerializeObject(e.Package));
#endif
            var key = e.Package.Key;
            System.Diagnostics.Debug.Assert(_commandHandle != null);
            
            switch (key)
            {
                case MsgTypes.Bye:
                    _client.Close();
                    break;
                case MsgTypes.Echo:                   
                    _logger.Trace(e.Package.Key);
                    break;
                case MsgTypes.Ping:
                    //_client.Send(MsgPacket.CreateNewInstance(MsgTypes.Echo, DateTime.Now.ToString()).ToBytes());
                    _commandHandle.PingReply();
                    _logger.Trace(e.Package.Key);
                    break;
                case MsgTypes.PingReply:                    
                    break;
                case MsgTypes.GetVersion: //获取版本
                    _commandHandle.GetVersionReply(e);
                    break;
                case MsgTypes.CheckUpdate:  //检查更新
                    _commandHandle.CheckUpdateReply(e,_updateChannel);
                    break;
                case MsgTypes.WebSiteInfo: //获取本地站点信息
                    _commandHandle.WebSiteInfoReply(e);
                    break;
                case MsgTypes.WebSiteAdd: //创建站点
                    _commandHandle.WebSiteAddReply(e);
                    break;
                case MsgTypes.WebSiteEdit: //修改站点
                    _commandHandle.WebSiteEditReply(e);
                    break;
                case MsgTypes.WebSiteDelete: //删除站点
                    _commandHandle.WebSiteDeleteReply(e);
                    break;
                case MsgTypes.AppPoolInfo: //查询程序池
                    _commandHandle.AppPoolInfoReply(e);
                    break;
                case MsgTypes.AppPoolAdd: //创建程序池
                    _commandHandle.AppPooAddReply(e);
                    break;
                case MsgTypes.AppPoolEdit: //修改程序池
                    _commandHandle.WebSiteEditReply(e);
                    break;
                case MsgTypes.AppPoolDelete: //删除程序池
                    _commandHandle.AppPoolDeleteReply(e);
                    break;
                case MsgTypes.DownLoad: //下载文件
                    _commandHandle.DownLoadReply(e);
                    break;
                case MsgTypes.Upload: //上传文件
                    _commandHandle.UploadReply(e);
                    break;
                case MsgTypes.CheckSiteName: //检测站点名称
                    _commandHandle.CheckSiteNameReply(e);
                    break;
                case MsgTypes.CheckPoolName: //检测程序池名称
                    _commandHandle.CheckPoolNameReply(e);
                    break;
                default:
                    break;
            }
        }

        private void Client_Closed(object sender, EventArgs e)
        {
            _isLive = false;
            _logger.Info("socket连接关闭");

        }

        private void Client_Connected(object sender, EventArgs e)
        {
            _isLive = true;
            _logger.Info("socket连接成功");
            StartPing();
        }

        

        
    }
}
